home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / CONVOLVE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  8.7 KB  |  397 lines

  1.  
  2. /* convolve.c - by Tom McReynolds, SGI */
  3.  
  4. /* Using the accumulation buffer for fast convolutions. */
  5.  
  6. #include <GL/glut.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. /* convolution choices */
  12. enum {CONV_NONE, 
  13.       CONV_BOX_3X3,
  14.       CONV_BOX_5X5,
  15.       CONV_SOBEL_X,
  16.       CONV_LAPLACE
  17. };
  18.  
  19. /* Filter contents and size */
  20. typedef struct {
  21.   GLfloat scale; /* 1/scale applied to image to prevent overflow */
  22.   GLfloat bias; /* for biasing images */
  23.   int rows;
  24.   int cols;
  25.   GLfloat *array;
  26. } Filter;
  27.  
  28. Filter *curmat; /* current filter to use for redrawing */
  29.  
  30. /* identity filter */
  31. void
  32. identity(Filter *mat)
  33. {
  34.   int n, size;
  35.   size = mat->rows * mat->cols;
  36.  
  37.   mat->array[0] = 1.f;
  38.   for(n = 1; n < size; n++)
  39.     mat->array[n] = 0.f;
  40.  
  41.   mat->scale = 1.f;
  42.   mat->bias = 0.f;
  43. }
  44.  
  45.  
  46. /* create a new filter with identity filter in it */
  47. Filter *
  48. newfilter(int rows, int cols)
  49. {
  50.   Filter *mat;
  51.  
  52.   mat = (Filter *)malloc(sizeof(Filter));
  53.   mat->rows = rows;
  54.   mat->cols = cols;
  55.   mat->array = (GLfloat *)malloc(rows * cols * sizeof(GLfloat));
  56.   identity(mat);
  57.   
  58.   return mat;
  59. }
  60.  
  61.  
  62. /* doesn't re-initialize matrix */
  63. void
  64. resize(Filter *mat, int rows, int cols)
  65. {
  66.   if(mat->rows != rows ||
  67.      mat->cols != cols) {
  68.     free(mat->array);
  69.     mat->array = (GLfloat *)realloc(mat->array, rows * cols * sizeof(GLfloat));
  70.   }
  71.   mat->rows = rows;
  72.   mat->cols = cols;
  73. }
  74.  
  75.  
  76. /* box filter blur */
  77. void
  78. box(Filter *mat)
  79. {
  80.   int n, count;
  81.   GLfloat blur;
  82.  
  83.   count = mat->cols * mat->rows;
  84.   blur = 1.f/count;
  85.   for(n = 0; n < count; n++)
  86.      mat->array[n] = blur;
  87.  
  88.   mat->scale = 1.f;
  89.   mat->bias = 0.f;
  90. }
  91.  
  92. /* sobel filter */
  93.  
  94. void
  95. sobel(Filter *mat)
  96. {
  97.   static GLfloat sobel[] = {-.5f, 0.f, .5f,
  98.                             -1.f, 0.f, 1.f,
  99.                             -.5f, 0.f, .5f};
  100.  
  101.   /* sobel is fixed size */
  102.   resize(mat, 3, 3); /* will do nothing if size is right already */
  103.   
  104.   memcpy(mat->array, sobel, sizeof(sobel));
  105.  
  106.   mat->scale = 2.f;
  107.   mat->bias = 0.f;
  108. }
  109.  
  110. /* laplacian filter */
  111. void
  112. laplace(Filter *mat)
  113. {
  114.   static GLfloat laplace[] = {  0.f, -.25f,   0.f,
  115.                               -.25f,   1.f, -.25f,
  116.                                 0.f, -.25f,   0.f};
  117.  
  118.   /* sobel is fixed size */
  119.   resize(mat, 3, 3); /* will do nothing if size is right already */
  120.   
  121.   memcpy(mat->array, laplace, sizeof(laplace));
  122.  
  123.   mat->scale = 4.f;
  124.   mat->bias = .125f;
  125. }
  126.  
  127. /* add menu callback */
  128.  
  129. void menu(int filter)
  130. {
  131.   switch(filter) {
  132.     case CONV_NONE:
  133.       resize(curmat, 1,1);
  134.       identity(curmat);
  135.       break;
  136.     case CONV_BOX_3X3:
  137.       resize(curmat, 3, 3);
  138.       box(curmat);
  139.       break;
  140.     case CONV_BOX_5X5:
  141.       resize(curmat, 5, 5);
  142.       box(curmat);
  143.       break;
  144.     case CONV_SOBEL_X:
  145.       sobel(curmat);
  146.       break;
  147.     case CONV_LAPLACE:
  148.       laplace(curmat);
  149.       break;
  150.   }
  151.   glutPostRedisplay();
  152. }
  153.  
  154. int winWidth = 0;
  155. int winHeight = 0;
  156.  
  157. /* used to get current width and height of viewport */
  158. void
  159. reshape(int wid, int ht)
  160. {
  161.   glViewport(0, 0, wid, ht);
  162.   winWidth = wid;
  163.   winHeight = ht;
  164. }
  165.  
  166. /* ARGSUSED1 */
  167. void key(unsigned char key, int x, int y)
  168. {
  169.     if(key == '\033')
  170.         exit(0);
  171. }
  172.  
  173.  
  174. /*
  175. ** Create a single component texture map
  176. */
  177. GLfloat *make_texture(int maxs, int maxt)
  178. {
  179.     int s, t;
  180.     static GLfloat *texture;
  181.  
  182.     texture = (GLfloat *)malloc(maxs * maxt * sizeof(GLfloat));
  183.     for(t = 0; t < maxt; t++) {
  184.         for(s = 0; s < maxs; s++) {
  185.             texture[s + maxs * t] = ((s >> 4) & 0x1) ^ ((t >> 4) & 0x1);
  186.         }
  187.     }
  188.     return texture;
  189. }
  190.  
  191. enum {SPHERE = 1, CONE};
  192.  
  193. void
  194. render(void)
  195. {
  196.     /* material properties for objects in scene */
  197.     static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
  198.  
  199.     glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
  200.  
  201.     /*
  202.     ** Note: wall verticies are ordered so they are all front facing
  203.     ** this lets me do back face culling to speed things up.
  204.     */
  205.  
  206.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
  207.  
  208.     /* floor */
  209.     /* make the floor textured */
  210.     glEnable(GL_TEXTURE_2D);
  211.  
  212.     /*
  213.     ** Since we want to turn texturing on for floor only, we have to
  214.     ** make floor a separate glBegin()/glEnd() sequence. You can't
  215.     ** turn texturing on and off between begin and end calls
  216.     */
  217.     glBegin(GL_QUADS);
  218.     glNormal3f(0.f, 1.f, 0.f);
  219.     glTexCoord2i(0, 0);
  220.     glVertex3f(-100.f, -100.f, -320.f);
  221.     glTexCoord2i(1, 0);
  222.     glVertex3f( 100.f, -100.f, -320.f);
  223.     glTexCoord2i(1, 1);
  224.     glVertex3f( 100.f, -100.f, -520.f);
  225.     glTexCoord2i(0, 1);
  226.     glVertex3f(-100.f, -100.f, -520.f);
  227.     glEnd();
  228.  
  229.     glDisable(GL_TEXTURE_2D);
  230.  
  231.     /* walls */
  232.  
  233.     glBegin(GL_QUADS);
  234.     /* left wall */
  235.     glNormal3f(1.f, 0.f, 0.f);
  236.     glVertex3f(-100.f, -100.f, -320.f);
  237.     glVertex3f(-100.f, -100.f, -520.f);
  238.     glVertex3f(-100.f,  100.f, -520.f);
  239.     glVertex3f(-100.f,  100.f, -320.f);
  240.  
  241.     /* right wall */
  242.     glNormal3f(-1.f, 0.f, 0.f);
  243.     glVertex3f( 100.f, -100.f, -320.f);
  244.     glVertex3f( 100.f,  100.f, -320.f);
  245.     glVertex3f( 100.f,  100.f, -520.f);
  246.     glVertex3f( 100.f, -100.f, -520.f);
  247.  
  248.     /* ceiling */
  249.     glNormal3f(0.f, -1.f, 0.f);
  250.     glVertex3f(-100.f,  100.f, -320.f);
  251.     glVertex3f(-100.f,  100.f, -520.f);
  252.     glVertex3f( 100.f,  100.f, -520.f);
  253.     glVertex3f( 100.f,  100.f, -320.f);
  254.  
  255.     /* back wall */
  256.     glNormal3f(0.f, 0.f, 1.f);
  257.     glVertex3f(-100.f, -100.f, -520.f);
  258.     glVertex3f( 100.f, -100.f, -520.f);
  259.     glVertex3f( 100.f,  100.f, -520.f);
  260.     glVertex3f(-100.f,  100.f, -520.f);
  261.     glEnd();
  262.  
  263.  
  264.     glPushMatrix();
  265.     glTranslatef(-80.f, -60.f, -420.f);
  266.     glCallList(SPHERE);
  267.     glPopMatrix();
  268.  
  269.  
  270.     glPushMatrix();
  271.     glTranslatef(-20.f, -80.f, -500.f);
  272.     glCallList(CONE);
  273.     glPopMatrix();
  274.  
  275. }
  276.  
  277.  
  278.  
  279. void
  280. convolve(void (*draw)(void), Filter *mat)
  281. {
  282.   int i, j;
  283.   int imax, jmax;
  284.  
  285.   imax = mat->cols;
  286.   jmax = mat->rows;
  287.   for(j = 0; j < jmax; j++) {
  288.       for(i = 0; i < imax; i++) {
  289.         glViewport(-i, -j, winWidth - i, winHeight - j);
  290.         draw();
  291.         glAccum(GL_ACCUM, mat->array[i + j * imax]);
  292.       }
  293.   }
  294. }
  295.  
  296.  
  297. /* Called when window needs to be redrawn */
  298. void redraw(void)
  299. {
  300.     glClearAccum(curmat->bias,
  301.                  curmat->bias,
  302.                  curmat->bias,
  303.                  1.0);
  304.  
  305.     glClear(GL_ACCUM_BUFFER_BIT);
  306.  
  307.     convolve(render, curmat);
  308.  
  309.     glViewport(0, 0, winWidth, winHeight);
  310.  
  311.     glAccum(GL_RETURN, curmat->scale);
  312.  
  313.     glutSwapBuffers();
  314.  
  315.     if(glGetError()) /* to catch programming errors; should never happen */
  316.        printf("Oops! I screwed up my OpenGL calls somewhere\n");
  317. }
  318.  
  319.  
  320. const int TEXDIM = 256;
  321.  
  322. int
  323. main(int argc, char *argv[])
  324. {
  325.     GLfloat *tex;
  326.     static GLfloat lightpos[] = {50.f, 50.f, -320.f, 1.f};
  327.     static GLfloat sphere_mat[] = {1.f, .5f, 0.f, 1.f};
  328.     static GLfloat cone_mat[] = {0.f, .5f, 1.f, 1.f};
  329.     GLUquadricObj *sphere, *cone, *base;
  330.  
  331.     glutInit(&argc, argv);
  332.     glutInitWindowSize(512, 512);
  333.     glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_ACCUM|GLUT_DOUBLE);
  334.     (void)glutCreateWindow("accumulation buffer convolve");
  335.     glutDisplayFunc(redraw);
  336.     glutKeyboardFunc(key);
  337.     glutReshapeFunc(reshape);
  338.  
  339.     /* draw a perspective scene */
  340.     glMatrixMode(GL_PROJECTION);
  341.     glFrustum(-100., 100., -100., 100., 320., 640.); 
  342.     glMatrixMode(GL_MODELVIEW);
  343.  
  344.     /* turn on features */
  345.     glEnable(GL_DEPTH_TEST);
  346.     glEnable(GL_LIGHTING);
  347.     glEnable(GL_LIGHT0);
  348.  
  349.     /* place light 0 in the right place */
  350.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  351.  
  352.     /* remove back faces to speed things up */
  353.     glCullFace(GL_BACK);
  354.  
  355.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  356.  
  357.     /* make display lists for sphere and cone; for efficiency */
  358.  
  359.     glNewList(SPHERE, GL_COMPILE);
  360.     sphere = gluNewQuadric();
  361.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  362.     gluSphere(sphere, 20.f, 20, 20);
  363.     gluDeleteQuadric(sphere);
  364.     glEndList();
  365.  
  366.     glNewList(CONE, GL_COMPILE);
  367.     cone = gluNewQuadric();
  368.     base = gluNewQuadric();
  369.     glRotatef(-90.f, 1.f, 0.f, 0.f);
  370.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  371.     gluDisk(base, 0., 20., 20, 1);
  372.     gluCylinder(cone, 20., 0., 60., 20, 20);
  373.     gluDeleteQuadric(cone);
  374.     gluDeleteQuadric(base);
  375.     glEndList();
  376.  
  377.     glutCreateMenu(menu);
  378.     glutAddMenuEntry("none", CONV_NONE);
  379.     glutAddMenuEntry("box filter (3x3 blur)", CONV_BOX_3X3);
  380.     glutAddMenuEntry("box filter (5x5 blur)", CONV_BOX_5X5);
  381.     glutAddMenuEntry("Sobel(x direction)", CONV_SOBEL_X);
  382.     glutAddMenuEntry("Laplace", CONV_LAPLACE);
  383.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  384.  
  385.  
  386.     /* load pattern for current 2d texture */
  387.     tex = make_texture(TEXDIM, TEXDIM);
  388.     glTexImage2D(GL_TEXTURE_2D, 0, 1, TEXDIM, TEXDIM, 0, GL_RED, GL_FLOAT, tex);
  389.     free(tex);
  390.  
  391.     curmat = newfilter(1, 1);
  392.     identity(curmat);
  393.  
  394.     glutMainLoop();
  395.     return 0;             /* ANSI C requires main to return int. */
  396. }
  397.